package com.cychat.mall.service.impl;

import com.Cychat.commons.entity.pojo.*;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.cychat.mall.config.RabbitMQConfig;
import com.cychat.mall.mapper.*;
import com.cychat.mall.params.OneProductOrderParams;
import com.cychat.mall.params.OrdersParams;
import com.cychat.mall.params.SubStock;
import com.cychat.mall.service.OrderDetailService;
import com.cychat.mall.service.OrdersService;
import com.cychat.mall.service.ProductService;
import com.cychat.mall.service.ShoppingCartService;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * Auther: 刘俊  <br/>
 * Date: 2025-11-6:下午 7:14  <br/>
 * Description: 订单服务实现类
 */
@Service
public class OrdersServiceImpl extends ServiceImpl<OrdersMapper, Orders> implements OrdersService {
    @Autowired
    private OrdersMapper orderMapper;
    @Autowired
    private ProductMapper productMapper;
    @Autowired
    private ShoppingCartMapper shoppingCartMapper;
    @Autowired
    private AddressMapper addressMapper;
    @Autowired
    private ShoppingCartService shoppingCartService;
    @Autowired
    private OrderDetailService orderDetailService;
    @Autowired
    private ProductService productService;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private RabbitTemplate rabbitTemplate; // 用于发送消息到 RabbitMQ

    @Autowired
    private StringRedisTemplate stringRedisTemplate; // 用于操作字符串库存

    @Override
    public List<Orders> listByUserId(Long userId) {
        // 调用Mapper层方法查询用户订单列表
        return orderMapper.selectList(new LambdaQueryWrapper<Orders>().eq(Orders::getUserId, userId));
    }


    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<String> createOrder(Long userId, OrdersParams params) {
        //1.1查询出购物车的信息
        List<ShoppingCart> cartList = shoppingCartMapper.selectList(new LambdaQueryWrapper<ShoppingCart>()
                .eq(ShoppingCart::getUserId, userId)
                .in(ShoppingCart::getCartId, params.getCartIds()));
        //1.2查询地址信息
        Address address = addressMapper.selectById(params.getAddressId());
        if (address == null) {
            throw new IllegalArgumentException("地址不存在");
        }
        //1.3查询商品ids，从params.getCartIds()得到商品ID列表
        List<Integer> productIds = cartList.stream()
                .map(ShoppingCart::getProductId)
                .toList();

        //1.4查询商品信息，从数据库中查询出所有选中的商品信息
        List<Product> productList = productMapper.selectList(new LambdaQueryWrapper<Product>()
                .in(Product::getProductId, productIds));
        // 构建 productId -> Product 的映射，避免重复查库
        Map<Integer, Product> productMap = productList.stream()
                .collect(Collectors.toMap(Product::getProductId, p -> p));
        //5. 将购物车项按商家分组：merchantId -> List<ShoppingCart>
        Map<Integer, List<ShoppingCart>> merchantToCarts = cartList.stream()
                .collect(Collectors.groupingBy(cart -> {
                    Product product = productMap.get(cart.getProductId());
                    if (product == null) {
                        throw new IllegalStateException("商品不存在: " + cart.getProductId());
                    }
                    return product.getMerchantId();
                }));
        // 6. 为每个商家创建一个订单
        List<String> orders = new ArrayList<>();

        // 所有涉及的商品ID（用于加锁和预扣）
        Set<Integer> allProductIds = cartList.stream()
                .map(ShoppingCart::getProductId)
                .collect(Collectors.toSet());

        // 【关键】对所有商品加分布式锁（按ID排序避免死锁）
        List<RLock> locks = allProductIds.stream()
                .sorted()
                .map(id -> redissonClient.getLock("lock:stock:" + id))
                .toList();

try {
    // 一次性获取所有锁（最多等待 500ms，持有 10s）
    boolean locked = redissonClient.getMultiLock(locks.toArray(new RLock[0]))
            .tryLock(500, 10_000, TimeUnit.MILLISECONDS);
    if (!locked) {
        throw new RuntimeException("系统繁忙，请稍后重试");
    }

    // 检查并预扣 Redis 库存
    for (Integer productId : allProductIds) {
        Product product = productMap.get(productId);
        ShoppingCart cart = cartList.stream()
                .filter(c -> c.getProductId().equals(productId))
                .findFirst()
                .orElseThrow(() -> new IllegalStateException("购物车项异常"));

        // 1. 初始化 Redis 库存（如果不存在）
        String stockKey = "stock:" + productId;
        Boolean exists = stringRedisTemplate.hasKey(stockKey);
        if (Boolean.FALSE.equals(exists)) {
            // 从 DB 同步库存到 Redis（注意线程安全，但首次一般没问题）
            stringRedisTemplate.opsForValue().set(stockKey, String.valueOf(product.getStock()));
        }

        // 2. 获取当前 Redis 库存
        String stockStr = stringRedisTemplate.opsForValue().get(stockKey);
        int currentStock = Integer.parseInt(stockStr == null ? "0" : stockStr);

        if (currentStock < cart.getQuantity()) {
            throw new RuntimeException("商品库存不足: " + product.getName());
        }

        // 3. 预扣库存（Redis 减）
        stringRedisTemplate.opsForValue().decrement(stockKey, cart.getQuantity());
    }


    for (Map.Entry<Integer, List<ShoppingCart>> entry : merchantToCarts.entrySet()) {
        //获取商家ID
        Integer merchantId = entry.getKey();
        //获取该商家的购物车项
        List<ShoppingCart> carts = entry.getValue();
        //创建订单主记录
        Orders order = new Orders();
        String orderId = UUID.randomUUID().toString();
        order.setOrderId(orderId);
        order.setUserId(userId);
        order.setMerchantId(merchantId);
        order.setReceiveName(address.getReceiverName());
        order.setReceivePhone(address.getReceiverPhone());
        order.setReceiveAddress(new String(
                address.getProvince()
                        + address.getCity()
                        + address.getDistrict()
                        + address.getDetailAddress()));
        order.setRefundReason("");

        order.setUpdateTime(new Date());
        // 计算该商家的总金额
        BigDecimal totalAmount = BigDecimal.ZERO;
        List<OrderDetail> orderDetails = new ArrayList<>();
        ArrayList<SubStock> subStocks = new ArrayList<>();
        for (ShoppingCart cart : carts) {
            Product product = productMap.get(cart.getProductId());
            if (product == null) continue; // 理论上不会发生

            // 检查库存（可选，建议加）
            if (product.getStock() < cart.getQuantity()) {
                throw new IllegalStateException("商品库存不足: " + product.getName());
            }

            BigDecimal itemTotal = product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity()));
            totalAmount = totalAmount.add(itemTotal);

            // 构建订单详情
            OrderDetail detail = new OrderDetail();
            detail.setOrderId(orderId);
            detail.setProductId(product.getProductId());
            detail.setProductName(product.getName());
            detail.setProductImage(product.getImage());
            detail.setUnitPrice(product.getPrice());
            detail.setQuantity(cart.getQuantity());
            detail.setSubtotal(itemTotal);
            detail.setCreateTime(new Date());
            orderDetails.add(detail);//添加到订单详情列表
            //添加到库存减少列表
            subStocks.add(new SubStock(product.getProductId(), cart.getQuantity()));
        }
        order.setCreateTime(new Date());
        order.setUpdateTime(new Date());
        order.setTotalAmount(totalAmount);
        orderMapper.insert(order);//插入订单主记录
        // 8. 批量插入订单详情
        if (!orderDetails.isEmpty()) {
            orderDetailService.insertBatch(orderDetails); // 假设有批量插入方法
        }
        orders.add(orderId);//添加到订单ID列表
        System.out.println("<orders>" + orders);
    }

    // 发送延迟消息（15分钟后检查是否支付，用于释放库存）
    sendDelayReleaseMessage(orders, userId);

    //3.删除购物车中选中的商品
    shoppingCartService.deleteCartItems(userId, params.getCartIds());
    //5.返回结果
    return orders;
}catch (InterruptedException e) {
    Thread.currentThread().interrupt();
    throw new RuntimeException("获取锁中断", e);
} finally {
    // 释放所有锁
    locks.forEach(RLock::unlock);
}
    }




    private void sendDelayReleaseMessage(List<String> orderIds, Long userId) {
        for (String orderId : orderIds) {
            // 发送订单ID到延迟队列
            rabbitTemplate.convertAndSend(
                    RabbitMQConfig.ORDER_DELAY_EXCHANGE,
                    RabbitMQConfig.ORDER_DELAY_ROUTING_KEY,
                    orderId
            );
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public List<String> createOrderByProductId(Long userId, OneProductOrderParams params) {
        // 1. 查询地址信息
        Address address = addressMapper.selectById(params.getAddressId());
        if (address == null) {
            throw new IllegalArgumentException("地址不存在");
        }

        // 2. 查询商品信息
        Product product = productMapper.selectById(params.getProductId());
        if (product == null) {
            throw new IllegalArgumentException("商品不存在");
        }

        // 3. 构造一个虚拟的购物车项（用于复用后续逻辑）
        ShoppingCart virtualCart = new ShoppingCart();
        virtualCart.setUserId(userId);
        virtualCart.setProductId(product.getProductId());
        virtualCart.setQuantity(1); // 默认购买数量为1，可根据需求扩展

        List<ShoppingCart> cartList = Collections.singletonList(virtualCart);

        // 4. 按商家分组（虽然只有一个商品，但保持结构一致）
        Map<Integer, List<ShoppingCart>> merchantToCarts = new HashMap<>();
        merchantToCarts.put(product.getMerchantId(), cartList);

        // 5. 所有涉及的商品ID（用于加锁）
        Set<Integer> allProductIds = Collections.singleton(product.getProductId());

        // 【关键】对商品加分布式锁（按ID排序避免死锁）
        List<RLock> locks = allProductIds.stream()
                .sorted()
                .map(id -> redissonClient.getLock("lock:stock:" + id))
                .toList();

        try {
            // 一次性获取所有锁（最多等待 500ms，持有 10s）
            RLock multiLock = redissonClient.getMultiLock(locks.toArray(new RLock[0]));
            boolean locked = multiLock.tryLock(500, 10_000, TimeUnit.MILLISECONDS);
            if (!locked) {
                throw new RuntimeException("系统繁忙，请稍后重试");
            }

            // 6. 检查并预扣 Redis 库存
            for (Integer productId : allProductIds) {
                String stockKey = "stock:" + productId;
                Boolean exists = stringRedisTemplate.hasKey(stockKey);
                if (Boolean.FALSE.equals(exists)) {
                    // 从 DB 同步库存到 Redis
                    stringRedisTemplate.opsForValue().set(stockKey, String.valueOf(product.getStock()));
                }

                String stockStr = stringRedisTemplate.opsForValue().get(stockKey);
                int currentStock = Integer.parseInt(stockStr == null ? "0" : stockStr);

                // 虚拟购物车中该商品数量为1
                if (currentStock < 1) {
                    throw new RuntimeException("商品库存不足: " + product.getName());
                }

                // 预扣库存
                stringRedisTemplate.opsForValue().decrement(stockKey, 1);
            }

            // 7. 创建订单
            List<String> orders = new ArrayList<>();
            for (Map.Entry<Integer, List<ShoppingCart>> entry : merchantToCarts.entrySet()) {
                Integer merchantId = entry.getKey();
                List<ShoppingCart> carts = entry.getValue();

                Orders order = new Orders();
                String orderId = UUID.randomUUID().toString();
                order.setOrderId(orderId);
                order.setUserId(userId);
                order.setMerchantId(merchantId);
                order.setReceiveName(address.getReceiverName());
                order.setReceivePhone(address.getReceiverPhone());
                order.setReceiveAddress(
                        address.getProvince() +
                                address.getCity() +
                                address.getDistrict() +
                                address.getDetailAddress()
                );
                order.setRefundReason("");
                order.setTotalAmount(BigDecimal.ZERO);
                order.setCreateTime(new Date());
                order.setUpdateTime(new Date());

                BigDecimal totalAmount = BigDecimal.ZERO;
                List<OrderDetail> orderDetails = new ArrayList<>();
                for (ShoppingCart cart : carts) {
                    BigDecimal itemTotal = product.getPrice().multiply(BigDecimal.valueOf(cart.getQuantity()));
                    totalAmount = totalAmount.add(itemTotal);

                    OrderDetail detail = new OrderDetail();
                    detail.setOrderId(orderId);
                    detail.setProductId(product.getProductId());
                    detail.setProductName(product.getName());
                    detail.setProductImage(product.getImage());
                    detail.setUnitPrice(product.getPrice());
                    detail.setQuantity(cart.getQuantity());
                    detail.setSubtotal(itemTotal);
                    detail.setCreateTime(new Date());
                    orderDetails.add(detail);
                }
                order.setTotalAmount(totalAmount);
                orderMapper.insert(order);
                if (!orderDetails.isEmpty()) {
                    orderDetailService.insertBatch(orderDetails);
                }
                orders.add(orderId);
            }

            // 8. 发送延迟消息（15分钟后检查是否支付，用于释放库存）
            sendDelayReleaseMessage(orders, userId);

            // 9. 返回订单ID列表
            return orders;

        } catch (InterruptedException e) {
            Thread.currentThread().interrupt();
            throw new RuntimeException("获取锁中断", e);
        } finally {
            // 释放所有锁
            locks.forEach(RLock::unlock);
        }
    }
}